#encoding=utf-8
#!/usr/bin/env python

import json
import os
import os.path
import re
#from system.core.base_service import BaseService

"""
Class       : Monitor
Description : A class which handle server data sampling
"""

class Monitor(object):

    """
    __arguments: moitor arguments, alaways be None
    """
    __arguments = None

    """
    __fmeminfo: file /proc/meminfo
    """
    __proc_meminfo = "/proc/meminfo"

    """
    __fstab: file /etc/fstab
    """
    __etc_fstab    = "/etc/fstab"

    """
    __proc_stat: cpu status information
    """
    __proc_stat    = "/proc/stat"

    """
    __proc_cpuinfo: cpu information
    """
    __proc_cpuinfo = "/proc/cpuinfo"

    """
    constructor: constructor for class monitor
    """
    def __init__(self, arguments = None):
        super(Monitor, self).__init__()
        self.__arguments = arguments
        return


    """
    invoke: invoke method for getting server sampleing information 
    """
    def invoke(self):
        success = True
        message = ""
        resultDict = None

        """
        get memory inforation 
        """
        memInfo = self.__get_memory_info()
        if memInfo["success"] == False:
            success = False
            message = memInfo["message"]
            return

        """
        get disk information
        """
        diskInfo = self.__get_disk_usage_info()
        if diskInfo["success"] == False:
            success = False
            message = diskInfo["message"]
            return

        """
        get cpu information
        """
        cpuInfo  = self.__get_cpu_info()
        if cpuInfo["success"] == False:
            success = False
            message = cpuInfo["message"]
            return

        resultDict           = dict()
        resultDict["cpu"]    = cpuInfo["info"]
        resultDict["disk"]   = diskInfo["info"]
        resultDict["memory"] = memInfo["info"]

        if success == False:
            pass
        else:
            pass
        return


    """
    __get_memory_info: get memory information from server
    """
    def __get_memory_info(self):
        fp     = None 
        result = dict(success = True, message = '', info = dict())
        memKeyList = ["MemTotal", "MemFree"]
        try:
            fp = open(self.__proc_meminfo, "r")
            while True:
                line = fp.readline()
                if not line:
                    break;
                else:
                    reLine = re.match("([\w]+):([\s]+)(.*)", line)
                    if reLine and reLine.group(1) in memKeyList:
                        key   = reLine.group(1)
                        value = reLine.group(3)
                        result["info"][key.lower()] = value
                        continue
                    del reLine
        except Exception,e:
            result["success"] = False
            result["message"] = str(e)
        finally:
            if fp is not None:
                fp.close()
        return result


    """
    __get_disk_usage_info: get disk usage information
    """
    def __get_disk_usage_info(self):
        fp     = None
        result = dict(success = True, message = '', info = None)
        try:
            fsInfos        = list()
            fsDiskInfos    = list()
            excludeKeyList = ["/boot", "swap", "/dev/shm", "/dev/pts", "/sys", "proc"]
            """
            Parse information from file "/etc/fstab" 
            """
            fp = open(self.__etc_fstab, "r")
            while True:
                line = fp.readline()
                if not line:
                    break;
                else:
                    if line == "\n" or re.match("^#(.*)", line):
                        continue
                    else:
                        fsInfo         = dict()
                        fsInfoList     = re.split("[\s]+", line)
                        if fsInfoList[1] not in excludeKeyList:
                            fsInfo["fs_name"] = fsInfoList[0]
                            fsInfo["fs_dir"]  = fsInfoList[1]
                            fsInfos.append(fsInfo)
                        del fsInfo, fsInfoList
                del line

            """
            Get disk information from parser list
            """
            for i in xrange(0, len(fsInfos)):
                vfsNode = None
                vfsInfo = None
                if os.path.exists(fsInfos[i]["fs_dir"]):
                    vfsNode = fsInfos[i]["fs_dir"]
                else:
                    vfsNode = fsInfos[i]["fs_name"]
                vfsNode = os.statvfs(vfsNode)
                if vfsNode.f_blocks > 0:
                    dirname       = fsInfos[i]["fs_dir"]
                    frgSize       = vfsNode.f_frsize
                    vfsTotal      = frgSize * vfsNode.f_blocks
                    vfsFree       = frgSize * vfsNode.f_bfree 
                    vfsAvail      = frgSize * vfsNode.f_bavail
                    vfsPrecentage = (100 * (vfsTotal - vfsFree)) / (vfsTotal - vfsFree + vfsAvail)
                    vfsInfo       = dict(name = fsInfos[i]["fs_dir"], total = vfsTotal, free = vfsFree, avail = vfsAvail, precentage = vfsPrecentage)
                    fsDiskInfos.append(vfsInfo)
                    del vfsInfo

            result["info"] = fsDiskInfos
        except Exception,e:
            result["success"] = False
            result["message"] = "[Server][__get_disk_usage_info] " + str(e)
        finally:
            del fsInfos
            del fsDiskInfos
            if fp is not None:
                fp.close()
        return result


    """
    __get_cpu_info: get cpu information
    """
    def __get_cpu_info(self):

        idle          = 0
        total         = 0
        allIdle       = 0
        cpuBlocks     = list()
        cpuStatBlocks = list()
        cpuInfoBlocks = list()
        fpStat        = None
        fpCpuInfo     = None

        result    = dict(success = True, message = '', info = dict())
        try:
            """
            Get cpus idle
            """
            fpStat = open(self.__proc_stat, "r")
            while True:
                line   = fpStat.readline()
                if not line:
                    break
                else:
                    match_obj = re.match("^cpu([\d\s])(.*)", line.rstrip("\n"))
                    if match_obj:
                        total = 0
                        fill = match_obj.group(1)
                        info = re.split("[\s]+", line.rstrip("\n"))
                        for i in xrange(1, len(info)):
                            total += int(info[i])
                        idle = (int(info[4]) * 100) / total
                        if fill.isdigit():
                            cpuStatBlocks.append(dict(index = int(fill), idle = idle))
                        else:
                            allIdle = idle
                        del info 
                del line

            """
            Get cpus detail info
            """
            currentCpuIndex = -1
            fpCpuInfo = open(self.__proc_cpuinfo, "r")
            while True:
                line = fpCpuInfo.readline()
                if not line:
                    break;
                elif line == "\n":
                    continue
                else:
                    match_obj   = re.match("^([^:]+):([\s](.*))?$", line.rstrip("\n"))
                    column_name = match_obj.group(1).rstrip()
                    if column_name == "processor":
                        currentCpuIndex = int(match_obj.group(3))
                    elif column_name == "model name":
                        cpuInfoBlocks.append(dict(index = currentCpuIndex, model_name = match_obj.group(3)))
                    del match_obj
                del line

            """
            Construct cpuBlocks
            """
            for i in xrange(0, len(cpuStatBlocks)):
                for j in xrange(0, len(cpuInfoBlocks)):
                    if cpuStatBlocks[i]["index"] == cpuInfoBlocks[j]["index"]:
                        cpuBlocks.append(dict(index = cpuStatBlocks[i]["index"], model_name = cpuInfoBlocks[j]["model_name"], idle = cpuStatBlocks[i]["idle"]))
                        break

            result['info']['idle']  = allIdle
            result['info']['count'] = currentCpuIndex + 1
            result['info']['cpus']  = cpuBlocks
        except Exception,e:
            result["success"] = False
            result["message"] = "[Server][__get_disk_usage_info] " + str(e)
        finally:
            if fpStat is not None:
                fpStat.close()
            if fpCpuInfo is not None:
                fpCpuInfo.close()
            del cpuBlocks, cpuStatBlocks, cpuInfoBlocks
        return result

if __name__ == "__main__":
    monitor = Monitor()
    monitor.invoke()
